package com.winsdom.handler;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.winsdom.dto.PaymentReceiptImportDTO;
import com.winsdom.exception.BaseException;
import com.winsdom.exception.BusinessException;
import com.winsdom.exception.ExcelException;
import com.winsdom.result.Result;
import com.winsdom.utils.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartFile;

import javax.sound.sampled.DataLine;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 全局异常处理器，处理项目中抛出的业务异常
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @Autowired
    private AliOssUtil aliOssUtil;

    /**
     * 业务异常处理
     */
    @ExceptionHandler
    public Result businessHandle(BusinessException e) {
        log.error("异常信息：{}", e.getMessage());
        return Result.error(e.getErrorCode(), e.getErrorMessage());
    }

    @ExceptionHandler
    public Result exceptionHandler(BaseException ex) {
        log.error("异常信息：{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }

    /**
     * 校验参数异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleValidationException(MethodArgumentNotValidException ex) {
        // 将所有字段错误拼接成一个字符串（例如："id不能为空, name长度不能超过50"）
        String errorMessage = ex.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getDefaultMessage()) // 提取错误消息
                .collect(Collectors.joining(", "));     // 用逗号拼接

        return Result.error(errorMessage); // 直接返回错误字符串
    }

    /**
     * 处理IllegalArgumentException
     * @param ex
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result handleIllegalArgumentException(IllegalArgumentException ex) {
        String errorMsg = ex.getMessage();
        log.warn("异常信息: {}", errorMsg);  // 记录警告日志（非系统错误）
        return Result.error(400, errorMsg);  // 返回400错误码+原始异常信息
    }

    @ExceptionHandler(ExcelException.class)
    public Result handleExcelException(ExcelException ex) {
        String message = ex.getMessage();
        log.error("Excel导入异常: {}", message);

        MultipartFile file = ex.getFile();
        if (Objects.isNull(file)) {
            return Result.error(ex.getMessage());
        }

        try (InputStream inputStream = file.getInputStream()) {
            // 创建临时文件
            File errorFile = File.createTempFile("error_", "_" + file.getOriginalFilename());
            errorFile.deleteOnExit();

            // 处理Excel并添加错误信息
            processExcelWithError(inputStream, errorFile, message);

            // 上传到OSS
            String originalFilename = file.getOriginalFilename();
            String ossFileName = "excel_errors/" + UUID.randomUUID() + "_" + originalFilename;
            String ossUrl = aliOssUtil.upload(Files.readAllBytes(errorFile.toPath()), ossFileName);

            return Result.success("文件导入失败，可通过下载该上传的文件查看错误原因",ossUrl);

        } catch (Exception e) {
            log.error("处理Excel异常失败", e);
            throw new RuntimeException("生成错误报告失败", e);
        }
    }

    private void processExcelWithError(InputStream inputStream, File errorFile, String errorMessage) throws IOException {
        // 读取原始数据
        List<PaymentReceiptImportDTO> dataList = EasyExcel.read(inputStream)
                .head(PaymentReceiptImportDTO.class)
                .sheet()
                .doReadSync();

        // 写入新文件并添加错误信息
        try (ExcelWriter excelWriter = EasyExcel.write(errorFile, PaymentReceiptImportDTO.class).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            excelWriter.write(dataList, writeSheet);

            // 获取当前sheet
            Sheet sheet = excelWriter.writeContext().writeSheetHolder().getSheet();

            // 添加错误信息
            addErrorToSheet(sheet, errorMessage);

            // 手动刷新数据到文件
            excelWriter.finish();
        }
    }

    private void addErrorToSheet(Sheet sheet, String errorMessage) {
        // 创建样式
        Workbook workbook = sheet.getWorkbook();
        CellStyle style = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setColor(Font.COLOR_RED);
        font.setBold(true);
        style.setFont(font);

        // 添加错误信息行
        int lastRowNum = sheet.getLastRowNum();
        Row row = sheet.createRow(lastRowNum + 2); // 空一行更清晰

        Cell cell = row.createCell(0);
        cell.setCellValue("错误原因：");
        cell.setCellStyle(style);

        cell = row.createCell(1);
        cell.setCellValue(errorMessage);
        cell.setCellStyle(style);

        // 设置错误信息区域的列宽
        sheet.setColumnWidth(0, 15 * 256); // 15个字符宽度
        sheet.setColumnWidth(1, 50 * 256); // 50个字符宽度
    }

}
